unit BootPlots;

interface


uses DiagramFactory, datacontainer, pganalysistypesunit, apgabstractunit, classes,
   xmlintf, pgseriesunit, chartaxisunit, ifmmemoryunit, math, sysutils, ifmgdi;


type TBootType = (btSSB = 0, btFMean, btObj, btBanana);

const c_BootChartName : array[btSSB..btBanana] of string = ('SSB', 'F Mean', 'Object function', 'Banana (SSB vs. F)'); 

type
   BootChart = class(TasacsChart)
   private
      m_BootType : TBootType;
   protected
   public
      function CreateChartAxis(Axis : PgAxisType) : APgChartAxis; override;
      function CreateSeries(AOwner : TComponent; PrimaryChartAxis : APgChartAxis; MetaSeries : APgMetaSeries; XIndex : Integer) : APgSeries; override;
      constructor Create(AOwner : TComponent; ItemNode : IXMLNode; Caption : string; BootType : TBootType; datacontainer : TasacsDataContainer); reintroduce;
      property BootType : TBootType read m_BootType;
   end; // BootChart


   BootDiagram = class(TasacsDiagram)
   public
      constructor Create(AOwner : TComponent; datacontainer : TasacsDataContainer); reintroduce;
   end;


   BootSeries = class(PgSeries)
   protected
      function GetInternalValue(I : Integer; SeriesVariable : PgSeriesVariable; MetaSeries : ApgMetaSeries) : Double; override;
   end; // BootSeries


   SSBBananaAxis = class(PgChartAxis)
   protected
      function GetNumDimensionElms : Integer; override;
      function GetAxisLabel : string; override;
   end; // SSBBananaAxis


   SSBBananaAxisSeries = class(PgSeries)
   protected
      function GetInternalValue(I : Integer; SeriesVariable : PgSeriesVariable; MetaSeries : ApgMetaSeries) : Double; override;
   end; // SSBBananaAxisSeries

   ObjRankAxis = class(PgChartAxis)
   protected
      function GetNumDimensionElms : Integer; override;
      function GetAxisLabel : string; override;
   end; // ObjRankAxis

implementation


///////////////////////
// BootChart


function BootChart.CreateChartAxis(Axis : PgAxisType) : APgChartAxis;
begin
   Result := nil;
   case Axis of
      atx:
      begin
         case BootType of
            btSSB, btFMean:
               Result := StdYearAxis.Create(Self as IChart, Axis);
            btObj:
               Result := ObjRankAxis.Create(Self as IChart, Axis);
            btBanana:
               Result := SSBBananaAxis.Create(Self as IChart, Axis);
         end;
      end
   else
      Result := PgChartAxis.Create(Self as IChart, Axis);
   end; // case
end; // BootChart.CreateChartAxis


function BootChart.CreateSeries(AOwner : TComponent; PrimaryChartAxis : APgChartAxis; MetaSeries : APgMetaSeries; XIndex : Integer) : APgSeries;
begin
   Result := nil;
   case PrimaryChartAxis.axis of
      atX:
         if Assigned(MetaSeries) then
           Result := BootSeries.Create(AOwner, PrimaryChartAxis, MetaSeries, XIndex)
         else
         begin
            case BootType of
               btSSB, btFMean:
                  Result := StdYearAxisSeries.Create(AOwner, PrimaryChartAxis, MetaSeries, XIndex);
               btObj:
                  Result := TasacsAxisSeries.Create(AOwner, PrimaryChartAxis, MetaSeries, XIndex);
               btBanana:
                  Result := SSBBananaAxisSeries.Create(AOwner, PrimaryChartAxis, MetaSeries, XIndex);
            end;
         end
   end; // case
end; // BootChart.CreateSeries


constructor BootChart.Create(AOwner : TComponent; ItemNode : IXMLNode; Caption : string; BootType : TBootType; datacontainer : TasacsDataContainer);
var
   M : APgMetaSeries;
   seriesname, YAxisLbl : string;
   I : Integer;
begin
   m_BootType := BootType;
   inherited Create(AOwner, ItemNode, 'Chart', datacontainer);
   Self.Caption := Caption;
   ChartLegend := Caption;
   self.ShowChartLegend := true;
   if not Assigned(ItemNode) then
   begin
      ShowSeriesLegend := true;
      ShowMeanLegend := false;
//      ChartAxis[atX].ShowIntervalSeries := true;
      PlotType := ptCategorySingle;

      chartaxis[atX].ContinuousGroupData := true;
      chartaxis[atX].ShowMinorTick := false;
      chartaxis[atX].AxisLine := true;
      chartaxis[atX].ShowTickText := true;
      chartaxis[atX].ShowMajorTick := true;
      //chartaxis[atX].AxisLabelPosition := alpCenter;
      chartaxis[atX].ShowMajorGrid := true;
      case BootType of
         btObj:
         begin
            Self.ChartAxis[atx].Direction := north;
            Self.ChartAxis[aty].Direction := east;
            YAxisLbl := 'Obj'
         end;
         btBanana:
         begin
            YAxisLbl := 'F mean'
         end;
         btSSB: YAxisLbl := 'SSB';
         btFMean: YAxisLbl := 'F mean'
      end; // case
      chartaxis[aty].ShowLabel := true;
      chartaxis[aty].AxisLabel := YAxisLbl;
      chartaxis[aty].AxisLabelPosition := alpCenter;
      chartaxis[atY].ShowMajorGrid := true;
      chartaxis[aty].ShowMajorTick := true;
      chartaxis[aty].ShowMinorTick := false;
      chartaxis[aty].ShowTickText := true;
      chartaxis[aty].AxisLine := true;
      chartaxis[aty].DefaultAxisLabel := false;
      chartaxis[aty].DefaultMin := false;
      chartaxis[aty].MinValue := 0;
      // Setup meta series at y axis:
      with ChartAxis[atY].MetaSeries do
      begin
         case BootType of
            btSSB, btFMean:
            begin
               for I := 0 to 4 - 1 do
               begin
                  case I of
                     0: SeriesName := '10';
                     1: SeriesName := '50';
                     2: SeriesName := '90';
                     3: SeriesName := 'Org';
                  end; // case
                  M := TasacsMetaSeries.Create(ChartAxis[aty], nil, SeriesName, I + 1);
                  Add(Pointer(M));
                  M.BarPlot := false;
                  M.Scatter := true;
                  M.LinePlot := true;
               end;
            end;
            btObj:
            begin
               for I := 0 to 2 - 1 do
               begin
                  case I of
                     0: SeriesName := 'Obj';
                     1: SeriesName := 'Org';
                  end; // case
                  M := TasacsMetaSeries.Create(ChartAxis[aty], nil, SeriesName, I + 1);
                  Add(Pointer(M));
                  M.BarPlot := false;
                  M.Scatter := false;
                  M.LinePlot := true;
               end;
            end;
            btBanana:
            begin
               for I := 0 to 1 - 1 do
               begin
                  case I of
                     0: SeriesName := 'Banana';
                  end; // case
                  M := TasacsMetaSeries.Create(ChartAxis[aty], nil, SeriesName, I + 1);
                  Add(Pointer(M));
                  M.BarPlot := false;
                  M.Scatter := true;
                  M.LinePlot := false;
               end;
            end;
         end; // case
      end;
   end;
end; // BootChart.Create


///////////////////////////////
// BootDiagram


constructor BootDiagram.Create(AOwner : TComponent; datacontainer : TasacsDataContainer);
begin
   inherited Create(AOwner, nil, '', 'Bootstrap plots', '', datacontainer);
   NumDiagramColumns := 2;
   UseDefDiagramColumns := false;
end; // BootDiagram.Create


///////////////////////////////
// BootSeries


function GetPercentileIndex(NumObs, Perc : Integer) : Integer;
begin
   Result := round((NumObs - 1) * Perc / 100)
end; // GetPercentileIndex


function BootSeries.GetInternalValue(I : Integer; SeriesVariable : PgSeriesVariable; MetaSeries : ApgMetaSeries) : Double;
var
   S : Integer;
   M : FloatMatrix;
   F : FloatArray;
begin
   Result := nan;
   S := Self.MetaSeries.ChartAxis.MetaSeries.IndexOf(Pointer(Self.MetaSeries));
   with BootChart(PrimaryChartAxis.ChartComp).Datacontainer do
   with BootChart(PrimaryChartAxis.ChartComp) do
   case SeriesVariable of
      svIntervalDelta:
      begin
         case BootType of
            btSSB, btFMean:
            begin
                M := FloatMatrix(StdData[ord(stdBootSSB) + ord(BootType)]);
                if (M.GetSize(1) = 0) then exit;
                case S of
                  0: Result := M[GetPercentileIndex(M.GetSize(1), 10), MinCategory + I];
                  1: Result := M[GetPercentileIndex(M.GetSize(1), 50), MinCategory + I];
                  2: Result := M[GetPercentileIndex(M.GetSize(1), 90), MinCategory + I];
                  3:
                  begin
                     F := FloatArray(StdData[ord(stdBootSSBOrg) + ord(BootType)]);
                     Result := F[MinCategory + I];
                  end
                end; // case
            end;
            btObj:
            begin
               case S of
                  0: Result := FloatArray(StdData[ord(stdBootObj)])[I + MinCategory];
                  1: Result := FloatArray(StdData[ord(stdBootObjOrg)])[0]
               end; // case
            end
         else
            Result := inherited GetInternalValue(I, SeriesVariable, MetaSeries)
         end; // case
      end;
      svIntervalPointPos:
      begin
         case BootType of
            btBanana:
            begin
               F := FloatArray(StdData[ord(stdBootFMeanLastYear)]);
               Result := F[I + MinCategory];
            end;
         else
            Result := inherited GetInternalValue(I, SeriesVariable, MetaSeries)
         end; // case
      end;
   else
      Result := inherited GetInternalValue(I, SeriesVariable, MetaSeries)
   end; // case
end; // BootSeries.GetInternalValue


////////////////
// SSBBananaAxisSeries


function SSBBananaAxisSeries.GetInternalValue(I : Integer; SeriesVariable : PgSeriesVariable; MetaSeries : ApgMetaSeries) : Double;
var
   A : FloatArray;
begin
   Assert(IsAxisSeries);
   case SeriesVariable of
      svIntervalLow:
         with TasacsChart(PrimaryChartAxis.ChartComp).DataContainer do
         begin
            A := FloatArray(StdData[ord(stdBootSSBLastYear)]);
            Result := A[I + MinCategory];
         end
   else
      Result := inherited GetInternalValue(I, SeriesVariable, MetaSeries);
   end; // case
end; // SSBBananaAxisSeries.GetInternalValue


///////////////////
// SSBBananaAxis


function SSBBananaAxis.GetAxisLabel : string;
begin
   if DefaultAxisLabel then
      Result := 'SSB'
   else
      Result := inherited GetAxisLabel;
end; // SSBBananaAxis.GetAxisLabel


function SSBBananaAxis.GetNumDimensionElms : Integer;
begin
   with TasacsChart(ChartComp).DataContainer do
      Result := FloatMatrix(StdData[ord(stdBootSSBLastYear)]).GetSize(1); // Number of runs
end; // SSBBananaAxis.GetNumDimensionElms


///////////////////
// ObjRankAxis


function ObjRankAxis.GetAxisLabel : string;
begin
   if DefaultAxisLabel then
      Result := 'Rank'
   else
      Result := inherited GetAxisLabel;
end; // ObjRankAxis.GetAxisLabel


function ObjRankAxis.GetNumDimensionElms : Integer;
begin
   with BootChart(ChartComp).Datacontainer do
      Result := FloatArray(StdData[ord(stdBootObj)]).Capacity;
end; // ObjRankAxis.GetNumDimensionElms



end.
